/**
 * Copyright &copy; 2016-2017 <a href="http://git.oschina.net/whoamien/backend_management">Backend Management</a> All rights reserved.
 */
package com.xw.app.generator.vo;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.xw.util.JsonUtil;
import com.xw.util.StringUtil;

/**
 * The Class Table.
 *
 * @author Xi Wei
 */
public class Table implements Serializable{

	private String tableCatalog;
	private String tableSchema;
	private String tableName;
	private String tableComment;
	
	private List<Column> columnList = Lists.newArrayList();
	private List<KeyColumn> primaryKeyList = Lists.newArrayList();
	private List<KeyColumn> importedKeyList = Lists.newArrayList();
	private List<KeyColumn> exportedKeyList = Lists.newArrayList();
	
	private List<Column> searchColumnList = Lists.newArrayList();
	private List<Column> listColumnList = Lists.newArrayList();
	private List<Column> editColumnList = Lists.newArrayList();
	
	private List<String> preDefinedTableList = Arrays.asList("acctRole","acctUser","sysDict","sysMenu","systemConfig");
	
	/**
	 * Gets the table catalog.
	 *
	 * @return the table catalog
	 */
	public String getTableCatalog() {
		return tableCatalog;
	}
	
	/**
	 * Sets the table catalog.
	 *
	 * @param tableCatalog the new table catalog
	 */
	public void setTableCatalog(String tableCatalog) {
		this.tableCatalog = tableCatalog;
	}
	
	/**
	 * Gets the table schema.
	 *
	 * @return the table schema
	 */
	public String getTableSchema() {
		return tableSchema;
	}
	
	/**
	 * Sets the table schema.
	 *
	 * @param tableSchema the new table schema
	 */
	public void setTableSchema(String tableSchema) {
		this.tableSchema = tableSchema;
	}
	
	/**
	 * Gets the table name.
	 *
	 * @return the table name
	 */
	public String getTableName() {
		return tableName;
	}
	
	/**
	 * Sets the table name.
	 *
	 * @param tableName the new table name
	 */
	public void setTableName(String tableName) {
		this.tableName = tableName;
	}
	
	/**
	 * Gets the table comment.
	 *
	 * @return the table comment
	 */
	public String getTableComment() {
		return tableComment;
	}
	
	/**
	 * Sets the table comment.
	 *
	 * @param tableComment the new table comment
	 */
	public void setTableComment(String tableComment) {
		this.tableComment = tableComment;
	}
	
	/**
	 * Gets the column list.
	 *
	 * @return the column list
	 */
	public List<Column> getColumnList() {
		return columnList;
	}
	
	/**
	 * Sets the column list.
	 *
	 * @param columnList the new column list
	 */
	public void setColumnList(List<Column> columnList) {
		this.columnList = columnList;
	}
	
	/**
	 * Gets the primary key list.
	 *
	 * @return the primary key list
	 */
	public List<KeyColumn> getPrimaryKeyList() {
		return primaryKeyList;
	}
	
	/**
	 * Sets the primary key list.
	 *
	 * @param primaryKeyList the new primary key list
	 */
	public void setPrimaryKeyList(List<KeyColumn> primaryKeyList) {
		this.primaryKeyList = primaryKeyList;
	}

	
	
	/**
	 * Gets the primary key column name list.
	 *
	 * @return the primary key column name list
	 */
	public List<String> getPrimaryKeyColumnNameList() {
		List<String> primaryKeyColumnNameList = Lists.newArrayList();		
		primaryKeyList.forEach(x -> primaryKeyColumnNameList.add(x.getColumnName()));
		return primaryKeyColumnNameList;
	}
	
	
	/**
	 * 用于生成ManyToOne.
	 *
	 * @return the imported key list
	 */
	public List<KeyColumn> getImportedKeyList() {
		return importedKeyList;
	}
	
	/**
	 * Sets the imported key list.
	 *
	 * @param importedKeyList the new imported key list
	 */
	public void setImportedKeyList(List<KeyColumn> importedKeyList) {
		this.importedKeyList = importedKeyList;
	}
	
	/**
	 * Gets the exported key list.
	 *
	 * @return the exported key list
	 */
	public List<KeyColumn> getExportedKeyList() {
		return exportedKeyList;
	}
	
	/**
	 * Sets the exported key list.
	 *
	 * @param exportedKeyList the new exported key list
	 */
	public void setExportedKeyList(List<KeyColumn> exportedKeyList) {
		this.exportedKeyList = exportedKeyList;
	}
	
	
	/**
	 * Get the Columns to be used in the Search Panel
	 * @return
	 */
	public List<Column> getSearchColumnList() {
		return searchColumnList;
	}

	/**
	 * Set the Columns to be used in the Search Panel
	 * @param searchColumnList
	 */
	public void setSearchColumnList(List<Column> searchColumnList) {
		this.searchColumnList = searchColumnList;
	}

	/**
	 * Get the Columns to be used in the List Table
	 * @return
	 */
	public List<Column> getListColumnList() {
		return listColumnList;
	}

	/**
	 * Set the Columns to be used in the List Table
	 * @param listColumnList
	 */
	public void setListColumnList(List<Column> listColumnList) {
		this.listColumnList = listColumnList;
	}

	/**
	 * Get the Columns to be used in the Add/Edit page
	 * @return
	 */
	public List<Column> getEditColumnList() {
		return editColumnList;
	}

	/**
	 * Set the Columns to be used in the Add/Edit page
	 * @param editColumnList
	 */
	public void setEditColumnList(List<Column> editColumnList) {
		this.editColumnList = editColumnList;
	}

	/**
	 * Get the list of the column name for the imported keys
	 *
	 * @return the imported key column name list
	 */
	public List<String> getImportedKeyColumnNameList() {
		List<String> foreignKeyColumnNameList = Lists.newArrayList();
		importedKeyList.forEach(x -> foreignKeyColumnNameList.add(x.getColumnName()));
		return foreignKeyColumnNameList;
	}
	
	/**
	 * Gets the list of the column name for the exported keys.
	 *
	 * @return the exported key column name list
	 */
	public List<String> getExportedKeyColumnNameList() {
		List<String> foreignKeyColumnNameList = Lists.newArrayList();
		exportedKeyList.forEach(x -> foreignKeyColumnNameList.add(x.getColumnName()));
		return foreignKeyColumnNameList;
	}
	
	/**
	 * Checks if the table has imported key.
	 *
	 * @return true, if is checks for imported key
	 */
	public boolean isHasImportedKey(){
		return importedKeyList.isEmpty() ? false:true;
	}
	
	/**
	 * Checks if the table has exported key.
	 *
	 * @return true, if is checks for exported key
	 */
	public boolean isHasExportedKey(){
		return exportedKeyList.isEmpty() ? false:true;
	}
	
	/**
	 * Get the java class name for the table(Captialize Camel Case)
	 * for example: table_name -> TableName
	 *
	 * @return the table class name
	 */
	public String getTableClassName(){
		return StringUtil.toCapitalizeCamelCase(tableName);
	}
	
	/**
	 * Get the java variable name for the table(Camel Case)
	 * for example table_name -> tableName
	 *
	 * @return the table java name
	 */
	public String getTableJavaName(){
		return StringUtil.toCamelCase(tableName);
	}
	
	/**
	 * Gets the list of the import classes used in the Query class
	 *
	 * @return the query import list
	 */
	public List<String> getQueryImportList(){
		Set<String> importSet = Sets.newHashSet();		
		getColumnList().forEach(c -> importSet.addAll(c.getQueryImportList()));		
		return Lists.newArrayList(importSet);
	}
	
	/**
	 * Gets the list of import classes(include import classes, validation classes and join condition)
	 * Mainly used in the Model Class
	 *
	 * @return the import list
	 */
	public List<String> getImportList(){
		Set<String> importSet = Sets.newHashSet();
		for(Column column:getColumnList()){
			importSet.addAll(column.getImportList());
			importSet.addAll(column.getValidateImportList());
		}
		if(!getImportedKeyList().isEmpty()){
			importSet.add("javax.persistence.ManyToOne");
			importSet.add("javax.persistence.JoinColumns");
			importSet.add("javax.persistence.JoinColumn");
			importSet.add("javax.persistence.FetchType");
			importSet.add("javax.persistence.CascadeType");
		}
		return Lists.newArrayList(importSet);
	}
	
	/**
	 * Gets the other used Model class import (not predefined system model)
	 * @return
	 */
	public List<String> getImportModelList(){
		Set<String> importSet = Sets.newHashSet();
		if(!getImportedKeyList().isEmpty()){
			for(KeyColumn key : getImportedKeyList()){
				if(!preDefinedTableList.contains(key.getReferencedTableJavaField()) && !key.getReferencedTableName().equals(getTableName())){
					importSet.add(StringUtil.toCapitalizeCamelCase(key.getReferencedTableName()));
				}
			}
		}
		return Lists.newArrayList(importSet);
	}
	
	/**
	 * Get the used predefined system model class import
	 * @return
	 */
	public List<String> getImportPredefinedModelList(){
		Set<String> importSet = Sets.newHashSet();
		if(!getImportedKeyList().isEmpty()){
			for(KeyColumn key : getImportedKeyList()){
				if(preDefinedTableList.contains(key.getReferencedTableJavaField())){
					importSet.add(StringUtil.toCapitalizeCamelCase(key.getReferencedTableName()));
				}
			}
		}		
		return Lists.newArrayList(importSet);
	}
	
	/**
	 * Gets the display name.
	 * e.g table_name -> tableName
	 *
	 * @return the display name
	 */
	public String getDisplayName(){
		return StringUtil.toCamelCaseWithSpace(tableName);
	}
	
	/**
	 * Gets the import model and services in the Controller class(not predefined framework one)
	 *
	 * @return the additional import list
	 */
	public List<String> getAdditionalImportList(){
		Set<String> importSet = Sets.newHashSet();
		for(KeyColumn key : getImportedKeyList()){
			if(!preDefinedTableList.contains(key.getReferencedTableJavaField()) 
					&& !key.getReferencedTableName().equals(getTableJavaName())){
				importSet.add("app.model." + StringUtil.toCapitalizeCamelCase(key.getReferencedTableName()));
				importSet.add("app.service." + StringUtil.toCapitalizeCamelCase(key.getReferencedTableName()) + "Service");
			}
		}
		return Lists.newArrayList(importSet);
	}
	
	/**
	 * Gets the predefined import model and services in the Controller class
	 *
	 * @return the additional import list
	 */
	public List<String> getAdditionalPredefinedImportList(){
		Set<String> importSet = Sets.newHashSet();
		for(Column column : getColumnList()){
			if(column.getDictCode() != null){
				importSet.add("app.service.SysDictService");
			}
			if(column.getReferenceColumn() != null 
					&& !column.getReferenceColumn().getReferencedTableName().equals(getTableName())
					&& preDefinedTableList.contains(column.getReferenceColumn().getReferencedTableJavaField())){
				importSet.add("app.model." + StringUtil.toCapitalizeCamelCase(column.getReferenceColumn().getReferencedTableName()));
				importSet.add("app.service." + StringUtil.toCapitalizeCamelCase(column.getReferenceColumn().getReferencedTableName()) + "Service");
			}
		}
		return Lists.newArrayList(importSet);
	}
	
	/**
	 * Gets import list for system class (e.g java.util.List, java.util.Map)
	 *
	 * @return the additional system import list
	 */
	public List<String> getAdditionalSystemImportList(){
		Set<String> importSet = Sets.newHashSet();
		for(Column column : getColumnList()){
			if(column.getDictCode() != null){
				importSet.add("java.util.Map");
			}
			if(column.getReferenceColumn() != null && !column.getReferenceColumn().getReferencedTableName().equals(getTableName())){
				importSet.add("java.util.List");
			}
		}
		return Lists.newArrayList(importSet);
	}
	
	/**
	 * Get the Autowired Services used in the Controller
	 *
	 * @return the additional autowired
	 */
	public List<String> getAdditionalAutowired(){
		Set<String> autowiredSet = Sets.newHashSet();
		for(Column column : getColumnList()){
			if(column.getDictCode() != null){
				autowiredSet.add("sysDictService");
			}
			if(column.getReferenceColumn() != null && !column.getReferenceColumn().getReferencedTableName().equals(getTableName())){
				autowiredSet.add(StringUtil.toCamelCase(column.getReferenceColumn().getReferencedTableName()) + "Service");
			}
		}
		return Lists.newArrayList(autowiredSet);
	}
	
	/**
	 * Checks if is contains date field.
	 *
	 * @return true, if is contains date field
	 */
	public boolean isContainsDateField(){
		return getColumnList().stream().filter(c -> c.isDateField()).count() > 0;
	}
	
	/**
	 * Checks if is contains sql date field.
	 *
	 * @return true, if is contains sql date field
	 */
	public boolean isContainsSqlDateField(){
		return getColumnList().stream().filter(c -> c.isSqlDateField()).count() > 0;
	}
	
	/**
	 * Checks if is contains date time field.
	 *
	 * @return true, if is contains date time field
	 */
	public boolean isContainsDateTimeField(){
		return getColumnList().stream().filter(c -> c.isTimestampField()).count() > 0;
	}
	
	/**
	 * Checks if is contains time field.
	 *
	 * @return true, if is contains time field
	 */
	public boolean isContainsTimeField(){
		return getColumnList().stream().filter(c -> c.isTimeField()).count() > 0;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return JsonUtil.beanToJson(this);
	}
}
